﻿using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace MotionControl.Modules.PLC.Business
{
    public class NetInfo
    { 
        public string IP { get; set; }
        public int Port { get; set; }
    }
    public partial class PLCControl
    {
        public static PLCControl GetInstance { get => _instance.Value; }

        private static readonly Lazy<PLCControl> _instance = new Lazy<PLCControl>(() => new PLCControl(), true);
        private MODBUS_TCPIP _modbusTCP = null;
        private Thread _readThread;
        private bool _isConnected = false;
        private const int _monitorBytesLen = 22;
        private short[] monitorBuffer = new short[_monitorBytesLen];
        private static object _rwLock = new object();
        private int _retCode = 0;
        //private ILogger _logger;
        private PLCControl()
        {
            //_modbusTCP = new MODBUS_TCPIP();
            //_isConnected = _modbusTCP.Connect("192.168.10.12", 502, 500);
            //if (!_isConnected)
            //    return;
            //_readThread = new Thread(ReadCycle) { IsBackground = true };
            //_readThread.Start();
        }

        public void Start(NetInfo info)
        {
            _modbusTCP = new MODBUS_TCPIP();
            Task.Factory.StartNew( () =>
            {
                _isConnected = _modbusTCP.Connect(info.IP, info.Port, 500);
                if (!_isConnected)
                    return;
                _readThread = new Thread(ReadCycle) { IsBackground = true };
                _readThread.Start();
            });        
        }
        
        private void ReadCycle()
        {
            var retBool = false;
            try
            {
                while (true)
                {
                    Thread.Sleep(20);
                    lock (_rwLock)
                        retBool = _modbusTCP.ReadMultiWordData(0, _monitorBytesLen, monitorBuffer, out _retCode);
                    if (!retBool)
                        continue;
                    BytesParse(monitorBuffer);
                }
            }
            catch (Exception ex)
            {
                _modbusTCP.Close();
            }
           
        }
        private void WriteSingle(ushort addr, short val)
        {
            if (!_isConnected)
                return;
            var writeData = new short[1]{ val };
            lock (_rwLock)
                try
                {
                    _modbusTCP.WriteMultiWordData(addr, writeData, out _retCode);
                }
                catch{ }
        }
        private void WriteMulti(ushort addr, short[] data)
        {
            if (!_isConnected)
                return;
            lock (_rwLock)
                try
                {
                    _modbusTCP.WriteMultiWordData(addr, data, out _retCode);
                }
                catch { }           
        }
        ~PLCControl()
        {
            _modbusTCP.Close();
        }
    }
}
